﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LigerMVC.Common.Extensions;

namespace LigerMVC.Common
{
    /// <summary>
    /// QueryDescriptor的简化版
    /// </summary>
    public class QuerySimpleDescriptor
    {
        public QuerySimpleDescriptor()
        {
            IsAlso = true;
            this.Condition = new List<QueryCondition>();
        }
        public OrderByClause OrderBy { get; set; }
        public IList<QueryCondition> Condition { get; set; }
        //条件是否是 并操作
        public bool IsAlso { get; set; }
        public int PageSize { get; set; }
        public int PageIndex { get; set; }

        /// <summary>
        /// 获取全文搜索的conditions
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static IList<QueryCondition> GetConditions<TEntity>(string key)
        { 
            var type = typeof(TEntity);
            if (key.Contains(","))
            {
                var conditions = new List<QueryCondition>();
                foreach (var k in key.Split(','))
                {
                    conditions.AddRange(GetConditions(type, k, true));
                }
                return conditions;
            }
            return GetConditions(type, key, true);
        }

        public static readonly string[] SYSNAMES = new string[] { 
            "recordstatus", "createdate", "createuserid", "modifydate", "modifyuserid" 
        };
        public static IList<QueryCondition> GetConditions(Type type,string key,bool loadDeep = false)
        {
            var conditions = new List<QueryCondition>();
            try
            {
                foreach (var pro in type.GetProperties())
                {
                    if (!pro.CanWrite) continue;
                    if (loadDeep)
                    {
                        if (!TypeHelper.IsSimpleType(pro.PropertyType) && !TypeHelper.IsNullableType(pro.PropertyType) && !pro.PropertyType.IsGenericType)
                        {
                            var subConditions = GetConditions(pro.PropertyType, key, false);
                            foreach (var subCondition in subConditions)
                            {
                                if (string.IsNullOrEmpty(subCondition.Key)) continue;
                                subCondition.Key = pro.Name + "." + subCondition.Key;
                            }
                            conditions.AddRange(subConditions);
                        }
                    }
                    if (pro.Name.ToLower().EndsWith("guid")) continue;
                    if (pro.Name.EndsWith("ID")) continue; 
                    if (SYSNAMES.Contains(pro.Name.ToLower())) continue;
                    if (pro.PropertyType == typeof(string))
                    {
                        conditions.Add(new QueryCondition()
                        {
                            Key = pro.Name,
                            Value = key,
                            Operator = QueryOperator.Contains
                        });
                    }
                    else if (TypeHelper.IsNumber(pro.PropertyType))
                    {
                        if (new System.Text.RegularExpressions.Regex(@"^([0-9])[0-9]*(\.\w*)?$").IsMatch(key))
                        {
                            conditions.Add(new QueryCondition()
                            {
                                Key = pro.Name,
                                Value = DataHelper.ConvertValue(pro.PropertyType, key),
                                Operator = QueryOperator.Equal
                            });
                        }
                    }
                } 
            }
            catch
            { 
            }
            return conditions;
        }


        public void LoadCondition(FilterGroup filter)
        {
            if (filter == null) return;
            if (filter.rules == null) return;
            if (Condition == null) Condition = new List<QueryCondition>();
            foreach (var rule in filter.rules)
            {
                Condition.Add(ConvertToCondition(rule));
            }
        }

        public static QueryCondition ConvertToCondition(FilterRule rule)
        {
            var op = rule.op ?? "equal";
            op = op.ToLower();
            var k = OptDictionary.ContainsKey(op) ? OptDictionary[rule.op.ToLower()] : QueryOperator.Equal;
            return new QueryCondition()
            {
                Key = rule.field,
                Value = rule.value,
                ValueType = rule.type,
                Operator = k
            };
        }


        /// <summary>
        /// 处理类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Condition"></param>
        public static void PrepareCondition<T>(IEnumerable<QueryCondition> Condition)
        { 
            foreach (var field in Condition)
            {
                PrepareCondition<T>(field);
            }
        }
        /// <summary>
        /// 处理类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="field"></param>
        public static void PrepareCondition<T>(QueryCondition field)
        {
            var type = typeof(T); 
            var pro = type.GetProperty(field.Key);
            if (pro != null)
            {
                try
                {
                    if (pro.PropertyType == typeof(int?))
                    {
                        int? value = field.Value.ToString().ConvertTo<int>();
                        field.Value = value;
                    }
                    else
                    {
                        field.Value = DataHelper.ConvertValue(pro.PropertyType, field.Value);
                    }
                }
                catch (Exception err)
                {
                }
            }
            else if (!field.Key.Contains("."))
            {
                string complex = FindComplexClassName(type, field.Key);
                if (complex != null)
                {
                    field.Key = complex + "." + field.Key.Substring(complex.Length);
                }
            } 
        }

        private static string FindComplexClassName(Type type,string key)
        {
            foreach (var prop in type.GetProperties())
            {
                if (prop.PropertyType != null && !TypeHelper.IsSimpleType(prop.PropertyType) && !TypeHelper.IsNullableType(prop.PropertyType))
                {
                    if (key.StartsWith(prop.Name))
                    {
                        return prop.Name;
                    }
                }
            }
            return null;
        }

        public QueryDescriptor ConvertWithActiveRecord()
        {
            QueryDescriptor des = this.Convert();
            des.Condition = new FilterGroup()
            {
                op = "and",
                groups = new List<FilterGroup>()
                {
                    des.Condition 
                },
                rules = new List<FilterRule>()
                {
                    new FilterRule("RecordStatus","Inactive","notequal")
                }
            };
            return des;
        }

        public QueryDescriptor Convert()
        {
            var q = new QueryDescriptor()
            {
                OrderBy = new List<OrderByClause>(),
                PageSize = this.PageSize,
                PageIndex = this.PageIndex,
                Condition = new FilterGroup()
                {
                    op = this.IsAlso ?  "and" : "or",
                    rules = new List<FilterRule>()
                }
            };
            if (this.OrderBy != null)
            {
                q.OrderBy.Add(this.OrderBy);
            }
            if (this.Condition != null)
            {
                this.Condition.ToList().ForEach(a =>
                {
                    q.Condition.rules.Add(new FilterRule()
                    {
                        field = a.Key,
                        type = a.ValueType,
                        value = a.Value,
                        op = a.Operator.ToString()
                    });
                });
            }
            return q;
        }


        static Dictionary<string, QueryOperator> OptDictionary = new Dictionary<string, QueryOperator>
        {
            {QueryOperator.Equal.ToString().ToLower(), QueryOperator.Equal},
            {QueryOperator.GreaterThan.ToString().ToLower(), QueryOperator.GreaterThan},
            {QueryOperator.LessThan.ToString().ToLower(), QueryOperator.LessThan},
            {QueryOperator.GreaterThanOrEqual.ToString().ToLower(), QueryOperator.GreaterThanOrEqual},
            {QueryOperator.LessThanOrEqual.ToString().ToLower(), QueryOperator.LessThanOrEqual},
            {QueryOperator.In.ToString().ToLower(), QueryOperator.In},
            {QueryOperator.Contains.ToString().ToLower(), QueryOperator.Contains},
            {QueryOperator.Like.ToString().ToLower(), QueryOperator.Like},
            {QueryOperator.NotEqual.ToString().ToLower(), QueryOperator.NotEqual}
        };
    }
}
